   /*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
     Copyright (C) <2006-2009>  <Asaf Yarkoni asaf@yarkoni.net>

     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation, either version 3 of the License, or
     (at your option) any later version.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using MyPhotoIndex.ImageBank;
using MyPhotoIndex.DataAccess;
using MyPhotoIndex.Utilities;
using System.Security.Permissions;
using MyPhotoIndex.Settings;
using MyPhotoIndex.Interfaces;
using MyPhotoIndex.Plugins.ImageFormatProviders;
using System.IO;
using System.Collections.ObjectModel;
using MyPhotoIndex.Interfaces.Imaging;
using MyPhotoIndex.Interfaces.ImageFormatProviders;
using System.Drawing.Imaging;
using System.Threading;
using MyPhotoIndex.Interfaces.Plugins;
using MyPhotoIndex.Plugins;

namespace MyPhotoIndex
{
    public partial class FullScreenForm : Form
    {
        private                     FullScreenToolstrip m_toolstrip;

        private int                 m_selectedImage = -1;
        private Image               m_image;
        private Image               m_oldImage;
        private Rectangle           m_oldBounds;
        private Size                m_imageDrawSize;
        private Point               m_lastMousePosition;
        private Point               m_drawingPoint;
        private bool                m_valid = true;
        private bool                m_slideShowActive = false;

        public IImageCollection ImageList
        {
            get { return myPhotoIndexThumbnailViewer1.ImageList; }
            set { myPhotoIndexThumbnailViewer1.ImageList = value; }
        }

        public ReadOnlyCollection<int> SelectedList
        {
            get { return myPhotoIndexThumbnailViewer1.CheckedImages; }
        }

        public FullScreenForm()
        {
            InitializeComponent();

            pictureBox1.MouseClick += new MouseEventHandler(FullScreenForm_MouseClick);
            this.MouseWheel += new MouseEventHandler(FullScreenForm_MouseWheel);
        }

        void FullScreenForm_MouseWheel(object sender, MouseEventArgs e)
        {
            if (e.Delta > 0)
            {
                ZoomIn();
            }
            else
            {
                ZoomOut();
            }
        }

        public FullScreenForm(int selectedImage):
            this()
        {
            m_selectedImage = selectedImage;
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            m_valid = false;
            base.OnClosing(e);
        }

        void FullScreenForm_MouseClick(object sender, MouseEventArgs e)
        {
            //if (e.Button == MouseButtons.Right)
            //{
            //    contextMenuStrip1.Show(e.Location);
            //}
        }

        private void FullScreenForm_Load(object sender, EventArgs e)
        {
            m_toolstrip = new FullScreenToolstrip();
            m_toolstrip.Show(this);
            m_toolstrip.Top = 10;
            if (this.RightToLeft == RightToLeft.Yes)
            {
                m_toolstrip.Left = this.Size.Width - m_toolstrip.Size.Width - 20;
            }
            else
            {
                m_toolstrip.Left = 20;
            }

            if (m_selectedImage != -1)
            {
                myPhotoIndexThumbnailViewer1.SelectImage(m_selectedImage, true);
                myPhotoIndexThumbnailViewer1.ScrollToSelected();
            }
            else
            {
                myPhotoIndexThumbnailViewer1.SelectFirstImage();
            }
        }

        private void FullScreenForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            timer1.Stop();

            if (m_image != null)
            {
                m_image.Dispose();
                m_image = null;
            }

            m_toolstrip.Close();
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if ((keyData & Keys.Oemplus) == Keys.Oemplus &&
                (keyData & Keys.Control) == Keys.Control)
            {
                ZoomIn();
                return true;
            }

            if ((keyData & Keys.OemMinus) == Keys.OemMinus &&
                (keyData & Keys.Control) == Keys.Control)
            {
                ZoomOut();
                return true;
            }

            switch (keyData)
            {
                case (Keys)107://num+
                    ZoomIn();
                    return true;

                case (Keys)109://num-
                    ZoomOut();
                    return true;
            }

            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void FullScreenForm_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Escape:
                    this.Close();
                    break;
                case Keys.Space:
                    myPhotoIndexThumbnailViewer1.ToggleChecked(myPhotoIndexThumbnailViewer1.SelectedImages[0]);
                    break;
            }
        }

        private void myPhotoIndexThumbnailViewer1_SelectionChangedEvent(object sender, SelectedImageInfo e)
        {
            if (0 == myPhotoIndexThumbnailViewer1.SelectedImages.Count)
            {
                return;
            }

            IImageData imageData = Storage.Instance[myPhotoIndexThumbnailViewer1.SelectedImages[0]];
            if (imageData.LinkStatus == ImageLinkStatus.Valid)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(ImageChangedAsync), null);
            }
            else
            {
                if (m_slideShowActive == true)
                {
                    timer1.Enabled = true;
                }
            }
        }

        private void ImageChangedAsync(Object state)
        {
            if (0 == myPhotoIndexThumbnailViewer1.SelectedImages.Count)
            {
                return;
            }

            IImageData imageData = Storage.Instance[myPhotoIndexThumbnailViewer1.SelectedImages[0]];
            if (imageData.LinkStatus == ImageLinkStatus.Valid)
            {
                if(m_oldImage != null)
                {
                    m_oldImage = null;
                }
                m_oldBounds = new Rectangle(m_drawingPoint, m_imageDrawSize);

                IImageFormatProvider provider = imageData.FormatProvider;
                Image newImage = provider.LoadImage(imageData);
                if (m_image != null)
                {
                    m_oldImage = new Bitmap(m_image, m_imageDrawSize.Width, m_imageDrawSize.Height);
                    m_image.Dispose();
                    m_image = null;
                }

                m_image = newImage;

                if (m_valid == true)
                {
                    this.Invoke(new ThreadStart(ImageChanged));
                }
            }
        }

        private void ImageChanged()
        {
            //if (0 == myPhotoIndexThumbnailViewer1.SelectedImages.Count)
            //{
            //    return;
            //}

            //IImageData imageData = Storage.Instance[myPhotoIndexThumbnailViewer1.SelectedImages[0]];
            //if (imageData.LinkStatus == ImageLinkStatus.Valid)
            //{
            //    Bitmap m_oldImage = null;
            //    Rectangle m_oldBounds = new Rectangle(m_drawingPoint, m_imageDrawSize);

            //    IImageFormatProvider provider = imageData.FormatProvider;
            //    Image newImage = provider.LoadImage(imageData);
            //    if (m_image != null)
            //    {
            //        m_oldImage = new Bitmap(m_image, m_imageDrawSize.Width, m_imageDrawSize.Height);
            //        m_image.Dispose();
            //        m_image = null;
            //    }

            //    m_image = newImage;

            if (m_image != null)
            {
                bool isSmall = false;
                if (ImageAlgo.IsLandscapeImage(m_image.Size))
                {
                    if (m_image.Width < pictureBox1.Width &&
                       m_image.Height < pictureBox1.Height)
                    {
                        isSmall = true;
                    }
                }
                else
                {
                    if (m_image.Height < pictureBox1.Width &&
                       m_image.Width < pictureBox1.Height)
                    {
                        isSmall = true;
                    }
                }

                if (isSmall == true)
                {
                    UseActualSize(false);
                }
                else
                {
                    FitScreen(false);
                }

                Rectangle newRect = new Rectangle(m_drawingPoint, m_imageDrawSize);

                using (m_oldImage)
                using (Bitmap smallImage = new Bitmap(m_image, newRect.Width, newRect.Height))
                {
                    using (Graphics graphics = Graphics.FromHwnd(pictureBox1.Handle))
                    {
                        ReadOnlyCollection<ISlideShowEffectPlugin> plugins = Manager.GetPlugins<ISlideShowEffectPlugin>();
                        if (plugins.Count > 0)
                        {
                            ISlideShowEffectPlugin plugin = m_toolstrip.Effect;
                            if (plugin != null)
                            {
                                plugin.Transform(graphics, pictureBox1.ClientRectangle, m_oldImage, smallImage, m_oldBounds, newRect);
                            }
                            else
                            {
                                pictureBox1.Refresh();
                            }
                        }
                    }
                }
            }

            if (m_slideShowActive == true)
            {
                timer1.Enabled = true;
            }
        }

        private void pictureBox1_MouseEnter(object sender, EventArgs e)
        {
            this.Select();
        }

        public void StartSlideShow(int seconds)
        {
            myPhotoIndexThumbnailViewer1.Dock = DockStyle.None;
            pictureBox1.Dock = DockStyle.None;
            pictureBox1.Width = this.Width;
            pictureBox1.Height = this.Height;
            FitScreen();
            timer1.Interval = (seconds * 1000);
            timer1.Start();
            m_slideShowActive = true;
        }

        public void StopSlideShow()
        {
            myPhotoIndexThumbnailViewer1.Dock = DockStyle.Fill;
            pictureBox1.Dock = DockStyle.Fill;
            FitScreen();

            m_slideShowActive = false;

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            if (myPhotoIndexThumbnailViewer1.SelectedImages.Count > 0)
            {
                m_selectedImage = myPhotoIndexThumbnailViewer1.SelectedImages[0];
            }
            int id = myPhotoIndexThumbnailViewer1.SelectNextThumbnail();
            if (id == m_selectedImage)
            {
                m_toolstrip.SlideShowEnded();
                //StopSlideShow();
            }
        }

        internal void UseActualSize()
        {
            UseActualSize(true);
        }

        internal void UseActualSize(bool redraw)
        {
            m_imageDrawSize = m_image.Size;

            m_toolstrip.ImageZoomPercent = 100;
            //m_drawingPoint = new Point();

            CenterImage();

            if (redraw == true)
            {
                pictureBox1.Refresh();
            }
        }

        internal void FitScreen()
        {
            FitScreen(true);
        }

        internal void FitScreen(bool redraw)
        {
            if (m_image == null)
            {
                return;
            }

            m_imageDrawSize = ImageAlgo.GetImageProportionalSize(new SizeF(m_image.Width, m_image.Height), new SizeF(pictureBox1.Width, pictureBox1.Height));

            CenterImage();
            UpdateZoomValues();

            if (redraw == true)
            {
                pictureBox1.Refresh();
            }
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (m_imageDrawSize.Width <= pictureBox1.Width ||
                    m_imageDrawSize.Height <= pictureBox1.Height)
                {
                    return;
                }

                m_drawingPoint.X += (e.Location.X - m_lastMousePosition.X);
                m_drawingPoint.Y += (e.Location.Y - m_lastMousePosition.Y);

                int maxX = (pictureBox1.Width - m_imageDrawSize.Width);
                int maxY = (pictureBox1.Height - m_imageDrawSize.Height);

                if (m_drawingPoint.X > 0)
                {
                    m_drawingPoint.X = 0;
                }

                if (m_drawingPoint.Y > 0)
                {
                    m_drawingPoint.Y = 0;
                }

                if (m_drawingPoint.X < maxX)
                {
                    m_drawingPoint.X = maxX;
                }

                if (m_drawingPoint.Y < maxY)
                {
                    m_drawingPoint.Y = maxY;
                }

                m_lastMousePosition = e.Location;
                pictureBox1.Refresh();
            }
        }

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                m_lastMousePosition = e.Location;

                if (m_imageDrawSize.Width > pictureBox1.Width ||
                    m_imageDrawSize.Height > pictureBox1.Height)
                {
                    this.Cursor = Cursors.Hand;
                }
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (this.Cursor == Cursors.Hand)
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (m_image != null &&
                m_valid == true)
            {
                e.Graphics.DrawImage(m_image, new Rectangle(m_drawingPoint, m_imageDrawSize));
            }
        }

        internal void ZoomIn()
        {
            int stepX = m_imageDrawSize.Width / 10;
            int stepY = m_imageDrawSize.Height / 10;
            m_imageDrawSize = ImageAlgo.GetImageProportionalSize(new SizeF(m_image.Width, m_image.Height), new SizeF(m_imageDrawSize.Width + stepX, m_imageDrawSize.Height + stepY));

            CenterImage();

            UpdateZoomValues();
            pictureBox1.Refresh();
        }

        internal void ZoomOut()
        {
            int stepX = m_imageDrawSize.Width / 10;
            int stepY = m_imageDrawSize.Height / 10;

            Size fitSize = ImageAlgo.GetImageProportionalSize(new SizeF(m_image.Width, m_image.Height), new SizeF(pictureBox1.Width, pictureBox1.Height));
            int newWidth = Math.Max(m_imageDrawSize.Width - stepX, fitSize.Width);
            int newHeight = Math.Max(m_imageDrawSize.Height - stepY, fitSize.Height);

            m_imageDrawSize = ImageAlgo.GetImageProportionalSize(new SizeF(m_image.Width, m_image.Height), new SizeF(newWidth, newHeight));

            CenterImage();

            UpdateZoomValues();
            pictureBox1.Refresh();
        }

        internal void UpdateZoomValues()
        {
            double zoom = ((double)m_imageDrawSize.Width / (double)m_image.Width);
            double zoomPercent = (zoom * 100);
            m_toolstrip.ImageZoomPercent = (int)zoomPercent;
        }

        internal void CenterImage()
        {
            int X = (pictureBox1.Width - m_imageDrawSize.Width) / 2;
            int Y = (pictureBox1.Height - m_imageDrawSize.Height) / 2;
            m_drawingPoint = new Point(X, Y);
        }
    }
}